
export {}

const count: number = 100
console.log(count);


// Ts类型注解: 简单类型
let msg: string
msg = 'hello ts'

let age: number = 18 
let name: string = 'jack'
let isLoading: boolean = false
let nullValue: null = null
let undefineValue: undefined = undefined

console.log(age, name, isLoading, nullValue, undefineValue);


// Ts 数组类型注解

// 语法1: 类型 []
let arr1: number[]
arr1 = [100, 200]


// 语法2: Array<number>
let arr2: Array<number>
arr2 = [100, 200]

// 思考题:

// 第一中写法
let arr3: string[]
arr3 = ['100', '3000']


// 第二种写法:
let arr4: Array<string>
arr4 = ['200', '500']


// 联合类型:

let arr5: (string | number)[] = [11, 22, '字符串']

// 联合类型,  别名

type ItemType = (string | number)[]

let arr6: ItemType
let arr7: ItemType

arr6 = ['jack2', 100]
arr7 = ['字符串8', 900]


// 函数类型注解

// 函数声明

function add(a:number, b:number): number {
        return a + b
}

add(10, 20)

let res: number
res = add(1,2)
// 函数表达式

// 函数表达式 --- 分开注解

const add2 = (a: number, b: number): number => {
    return a + b
}

add2(1,2)

// 函数表达式 --- 整体注解(库文件会用. )
type AddFn = (a: number, b: number) => number

const add3: AddFn = (a, b) => {
    return a + b
}

add3(5, 6)


// 可选参数(注: 必须在所有参数的末尾)

function buildName(firstName:string, lastName?: string): string {
    if (lastName) {
        return `${firstName}${lastName}`
    } else {
        return `${firstName}`
    }
    
}

console.log(buildName('张三'));
console.log(buildName('张三', '李四'));

// 无返回值

function eachArr(arr9: number[]): void {
    arr9.forEach((item)=>console.log(item))
}

eachArr([1,2,3])

// 函数类型: 思考题

/**
 * 定义一个函数:  作用吧数组转换成  字符串,   数组可以是字符串和数字.  分隔符也可以自定义
 * 
 * 样例: arr2str ([1,2,3], '-')  →  '1-2-3'
 */

function arr2str(arr: (number | string)[], split: string): string {
    return arr.join(split)
}

console.log(arr2str([1,2,3],'-'));
console.log(arr2str([4, 5],'&'));

// interface 接口类型

// 基础语法
interface Person{
    name: string
    age: number
} 

let p: Person = {
    name: "jack",
    age: 18
}

// 场景一: 表单数据收集
interface LoginForm {
    username: string
    password: string
}

let form: LoginForm = {
    username: "jack",
    password: "1234556"
}

// 场景二: 渲染后端列表

interface Goods {
    id: string
    price: number
}

let list: Goods[] = [
    {
        id: '1001',
        price: 300
    }
]

list.forEach((item) => console.log(item.price))


// 接口--- 可选设置

interface Props {
    type: string
    size?: string
}

// 不传
let props: Props = {
    type: 'success'
}

// 传必须保证类型匹配
props = {
    type: 'success',
    size: "large"
}

// 接口--- 继承

// 不用继承写法
// // 原价商品
// interface GoodsType {
//     id: string
//     price: number
// }
// // 打折商品类型
// interface DisGoodsType {
//     id: string
//     price: number
//     disPrice: number
// }

// 使用继承的写法
// 原价商品类型
interface GoodsType {
    id: string
    price: number
}
// 打折商品类型
interface DisGoodsType extends GoodsType {
   disPrice: number
}


let apple: GoodsType = {
    id: '0001',
    price: 100
}
let apple2: DisGoodsType = {
    id: '0001',
    price: 100,
    disPrice: 90
}
console.log(apple, apple2);

// 接口---思考题 

/**
 * 数据格式
 * {
 * code: 200,
 * msg: 'success',
 * data: {
 *  title: '文章标题',
 *  content: '文章内容'
 * }
 * }
 */

interface Data{
    title: string
    content: string
}

interface ResData{
    code: number,
    msg: string,
    data: Data
}

let resE: ResData = {
    code: 200,
    msg: "success",
    data: {
        title: '文章标题',
        content: '文章内容'
    }
}

console.log(resE.data.title);

// type 实现  对象类型   注解

type Person2 = {
    name: string,
    age?: number
}

let p2: Person2 = {
    name: 'jack',
    age: 19
}

p2 = {
    name: 'zhangsan'
}

// type 模拟继承  (交叉类型   &)

// 父接口
type GoodsType2 = {
    id: string
    price: number
}

// 子接口
type DisGoodsType2 = GoodsType2 & {
    disPrice: number
}

let goods2: DisGoodsType2 = {
    id: '0004',
    price: 300,
    disPrice: 900
}


console.log(goods2.disPrice);


// 同名interface 
interface Item {
    name: string
}

interface Item {
    age: number
}

let item: Item = {
    name: 'jack',
    age: 88
}

console.log(item.age);

// 同名 type  会报错. 

type Item1 = {

}

// type Item1   

// type---思考题 

/**
 * 数据格式
 * {
 * code: 200,
 * msg: 'success',
 * data: {
 *  title: '文章标题',
 *  content: '文章内容'
 * }
 * }
 */

type Data2 = {
    title: string
    content: string
}

type ResData2 = {
    code: number
    msg: string
    data: Data2
}

let res2Data: ResData2 = {
    code:200,
    msg: 'success',
    data: {
        title: "标题",
        content: "内容"
    }
}

console.log(res2Data.data.content);


// 字面量类型

type Gender = '男' | '女'

let gender: Gender = "男"

// const

let str1 = '123'

const str2 = '456'

console.log(gender, str1, str2);

// 字面量--思考题

type Res = {
    code: 1001 | 1002 | 1003
    msg: string
}

let res5: Res = {
    msg: '接口成功',
    code: 1002
}

console.log(res5);


// 类型推论

let count2 = 100
count2 = 200
// count2 = false

function add5(a:number, b: number) {
    return a + b
    
}

const result3 = add5(1,2)


console.log(result3);


// 类型断言

// 未断言
const link1 = document.getElementById('link')
// link1.href  // 点  不出来. 

// 使用断言
const link2 = document.getElementById('link') as HTMLAnchorElement
link2.href  // 可以  点  出属性等. 

// 断言---注意事项

function log(foo:string | number) {
    console.log((foo as number).toFixed(2));
    
}

log(100)
// log("100")  // 报错: Uncaught TypeError


// 泛型---接口

// User 数据
interface User {
    name: string
    age: number
}

interface UserData {
    code: number
    msg: string
    data: User
}

// 货物  数据
interface Goods2 {
    id: number
    goodsName: string
}

interface GoodsData2{
    code: number
    msg: string
    data: Goods2
}

// 通过对比, 发现  上面的有的只有data 属性不同. 

// 上面的数据----泛型改造

// 1. 定义泛型  把可变的部分抽象成  泛型参数  T
// interface ResData8<T> {
//     code: number
//     msg: string
//     data: T
// }

// // 2. 定义具体类型   然后使用泛型的时候  传入到参数的位置
// interface User10 {
//     name: string
//     age: number
// }
// interface Goods10 {
//     id: number
//     goodsName: string
// }

// let useData: ResData8<User10> = {
//     code: 200,
//     msg: "success",
//     data: {
//         name: 'zhangsan',
//         age: 12
//     }
// }

// console.log(useData);


// let goodsData: ResData8<Goods10> = {
//     code: 200,
//     msg: "success",
//     data: {
//         id: 3,
//         goodsName: "衬衫"
//     }
// }

// console.log(goodsData);

//-----------泛型别名---------

// 上面的数据----泛型改造

// 1. 定义泛型  把可变的部分抽象成  泛型参数  T
type ResData8<T> = {
    code: number
    msg: string
    data: T
}

// 2. 定义具体类型   然后使用泛型的时候  传入到参数的位置
type User10 = {
    name: string
    age: number
}
type Goods10 =  {
    id: number
    goodsName: string
}

let useData: ResData8<User10> = {
    code: 200,
    msg: "success",
    data: {
        name: 'zhangsan',
        age: 12
    }
}

console.log(useData);


let goodsData: ResData8<Goods10> = {
    code: 200,
    msg: "success",
    data: {
        id: 3,
        goodsName: "衬衫"
    }
}

console.log(goodsData);


//-----------泛型函数---------

function createArray<T>(length: number, value: T) {
    let result = []
    for (let i = 0; i < length; i++) {
        result[i] = value;
    }

    return result
}

createArray<number>(4, 100)
createArray<string>(4, "200")

//-----------泛型约束---------

// function logLen<T>(obj: T) {
//     console.log(obj.length);
// }   // 报错: T 上面没有这个属性. 

interface lengthObj {
    length: number
}

function logLen1<T extends lengthObj>(obj: T) {
    console.log(obj.length);
}


logLen1({length: 10})
logLen1(['100'])
// logLen1(100) //报错: number 没有这个属性. 


// 综合案例---记录刷新次数. 和  时间

// 复杂的步骤: 先主线逻辑   后细节

function updateData() {
    // 1. 获取最新列表,  取到最后一项
    const list = getList()
    const lastItem = list[list.length - 1]
    // 2. 在上一条记录上  count  +   1  配合当前时间添加到列表尾部
    list.push({
        count: lastItem? lastItem.count + 1 : 1,
        time: getFormatTime()
    })
    // 3. 最新列表渲染到页面
    render(list)
    // 4. 最新列表存入到本地
    setList(list)

}

type ItemList = {
    count: number
    time: string
}
const KEY = 'ts-key'
function getList(): ItemList[] {
    return JSON.parse(localStorage.getItem(KEY) || '[]')
}

function setList(list: ItemList[]) {
    localStorage.setItem('KEY', JSON.stringify(list))
}


function getFormatTime() {
    const _time =  new Date();
    const h = _time.getHours()
    const m = _time.getMinutes()
    const s = _time.getSeconds()
    return `${h}:${m}:${s}`
}
function render(list: ItemList[]) {
    // 1. 把list中每个对象格式化成字符串
    const strArr = list.map((item) => {
        return `刷新次数为: ${item.count}, 刷新时间为: ${item.time}`
    })

    // 2. 调用 dom api 渲染到页面中
    const app = document.getElementById('app') as HTMLDivElement
    app.innerHTML = strArr.join('<br>')
}


updateData();